/*
实现了：
    消息的序列化和反序列化
    Rpc请求/应答、主题操作的请求/应答、服务操作的请求/应答
*/

#pragma once
#include "Detail.hpp"
#include "Fields.hpp"
#include "Abstract.hpp"

namespace RpcModule
{
    // 1. --------------------- Json请求和应答、Json序列化/反序列化实现 ----------------------
    class JsonMessage : public BaseMessage
    {
    public:
        using ptr = std::shared_ptr<JsonMessage>;
        // 序列化和反序列化
        virtual std::string Serialize() override
        {
            std::string retstring;
            bool ret = JSON::Serialize(_body, retstring);
            if (ret == false)
                return std::string();
            return retstring;
        }
        virtual bool UnSerialize(const std::string &message) override
        {
            return JSON::UnSerialize(message, _body);
        }

    protected:
        Json::Value _body;
    };

    class JsonRequest : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonRequest>;
    };

    class JsonResponse : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonResponse>;
        // 对于应答，需要提供应答消息的检测
        virtual bool Check() override
        {
            if (_body[KEY_RCODE].isNull() == true)
            {
                LOGERROR("应答码为空！");
                return false;
            }
            if (_body[KEY_RCODE].isIntegral() == false)
            {
                LOGERROR("应答码格式错误！");
                return false;
            }
            return true;
        }
        // 获取/设置应答码
        // 每一种应答方式，都需要提供获取和设置应答码的操作
        // 所以就将说去和设置应答码提取出来
        virtual RCode GetRcode() { return (RCode)_body[KEY_RCODE].asInt(); }
        virtual void SetRcode(RCode rcode) { _body[KEY_RCODE] = (int)rcode; }
    };

    // 2. ------------------------------- 三种请求类的实现 --------------------------------
    // Rpc请求
    class RpcRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<RpcRequest>;
        virtual bool Check() override
        {
            // Rpc请求包含：请求函数名称-string，请求参数-Json对象
            if (_body[KEY_METHOD].isNull() == true ||
                _body[KEY_METHOD].isString() == false)
            {
                LOGERROR("Rpc请求，传入的Rpc函数名称为空/格式错误");
                return false;
            }
            if (_body[KEY_PARAMS].isNull() == true ||
                _body[KEY_PARAMS].isObject() == false)
            {
                LOGERROR("Rpc请求，传入的Rpc参数为空/格式错误");
                return false;
            }
            return true;
        }
        // 设置Rpc方法名称
        void SetRpcMethod(const std::string &method_name)
        {
            _body[KEY_METHOD] = method_name;
        }
        // 设置Rpc参数
        void SetRpcParams(const Json::Value &params)
        {
            _body[KEY_PARAMS] = params;
        }
        // 获取Rpc方法名称/参数
        std::string GetRpcMethod() { return _body[KEY_METHOD].asString(); }
        Json::Value GetRpcParams() { return _body[KEY_PARAMS]; }
    };
    // 主题操作请求
    class TopicRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<TopicRequest>;
        virtual bool Check() override
        {
            if (_body[KEY_TOPIC_KEY].isNull() == true ||
                _body[KEY_TOPIC_KEY].isString() == false)
            {
                LOGERROR("主题操作请求：主题名称为空/格式错误");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true ||
                _body[KEY_OPTYPE].isIntegral() == false)
            {
                LOGERROR("主题操作请求：主题类型为空格式错误");
                return false;
            }
            // 只有当主题类型为发布主题时，才需要携带发布的信息
            if (_body[KEY_OPTYPE].asInt() == (int)TopicOptype::TOPIC_PUBLISH &&
                (_body[KEY_TOPIC_MSG].isNull() == true ||
                 _body[KEY_TOPIC_MSG].isString() == false))
            {
                LOGERROR("主题操作请求：主题发布时，发送消息为空/格式错误");
                return false;
            }
            return true;
        }
        // 设置主题名称
        void SetTopicKey(const std::string &key) { _body[KEY_TOPIC_KEY] = key; }
        // 设置主题类型
        void SetTopicOptype(TopicOptype optype) { _body[KEY_OPTYPE] = (int)optype; }
        // 设置主题消息
        void SetTopicMessage(const std::string &message) { _body[KEY_TOPIC_MSG] = message; }
        // 获取主题名称、主题类型、主题消息
        std::string GetTopicKey() { return _body[KEY_TOPIC_KEY].asString(); }
        TopicOptype GetTopicOptype() { return (TopicOptype)_body[KEY_OPTYPE].asInt(); }
        std::string GetTopicMessage() { return _body[KEY_TOPIC_MSG].asString(); }
    };
    // 服务操作请求
    typedef std::pair<std::string, int> Address;
    class ServiceRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<ServiceRequest>;
        virtual bool Check() override
        {
            // 服务操作请求：服务名称-string
            // 服务类型-enum枚举int类型
            // host对象，host中包含ip和port
            if (_body[KEY_METHOD].isNull() == true ||
                _body[KEY_METHOD].isString() == false)
            {
                LOGERROR("服务操作请求：服务方法名称为空/格式错误！");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true ||
                _body[KEY_OPTYPE].isIntegral() == false)
            {
                LOGERROR("服务操作请求：服务类型为空/格式错误！");
                return false;
            }
            // 当为服务发现时，我根本就不知道有什么主机，那么就不需要进行检测了
            if (_body[KEY_OPTYPE].asInt() != (int)(ServiceOptype::SERVICE_DISCOVERY) &&
                (_body[KEY_HOST].isNull() == true ||
                 _body[KEY_HOST].isObject() == false ||
                 _body[KEY_HOST][KEY_HOST_IP].isNull() == true ||
                 _body[KEY_HOST][KEY_HOST_IP].isString() == false ||
                 _body[KEY_HOST][KEY_HOST_PORT].isNull() == true ||
                 _body[KEY_HOST][KEY_HOST_PORT].isIntegral() == false))
            {
                LOGERROR("服务请求中主机地址信息错误！");
                return false;
            }
            return true;
        }
        // 设置服务名称
        void SetMethod(const std::string &name) { _body[KEY_METHOD] = name; }
        // 设置服务类型
        void SetOptype(ServiceOptype optype) { _body[KEY_OPTYPE] = (int)optype; }
        // 设置主机IP和端口号
        void SetHost(const Address &host)
        {
            Json::Value val;
            val[KEY_HOST_IP] = host.first;
            val[KEY_HOST_PORT] = host.second;
            _body[KEY_HOST] = val;
        }
        // 获取服务名称、服务类型、主机IP和端口号
        std::string GetMethod() { return _body[KEY_METHOD].asString(); }
        ServiceOptype GetOptype() { return (ServiceOptype)_body[KEY_OPTYPE].asInt(); }
        Address GetHost()
        {
            Address addr;
            addr.first = _body[KEY_HOST][KEY_HOST_IP].asString();
            addr.second = _body[KEY_HOST][KEY_HOST_PORT].asInt();
            return addr;
        }
    };

    // 3. ------------------------------- 三种应答类的实现 --------------------------------
    // Rpc应答
    class RpcResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<RpcResponse>;
        virtual bool Check() override
        {
            if (_body[KEY_RCODE].isNull() == true ||
                _body[KEY_RCODE].isIntegral() == false)
            {
                LOGERROR("Rpc应答：没有设置应答码/应答码设置格式错误！");
                return false;
            }
            if (_body[KEY_RESULT].isNull() == true)
            {
                LOGERROR("Rpc应答：应答结果为空！");
                return false;
            }
            return true;
        }
        // 设置应答结果 && 获取应答结果
        // 因为应答码的设置和获取在基类中已经被实现
        void SetResult(const Json::Value &result) { _body[KEY_RESULT] = result; }
        Json::Value GetResult() { return _body[KEY_RESULT]; }
    };
    // 主题操作应答
    class TopicResponse : public JsonResponse
    {
    public:
        // 对于主题操作的应答，只需要有应答码就可以了
        using ptr = std::shared_ptr<TopicResponse>;
    };
    // 服务操作应答
    // 服务操作比较复杂，因为有服务注册、服务上线/下线的应答
    // 还有服务发现的应答，服务发现的应答需要返回的是很多ip+端口
    class ServiceResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<ServiceResponse>;
        virtual bool Check() override
        {
            if (_body[KEY_RCODE].isNull() == true ||
                _body[KEY_RCODE].isIntegral() == false)
            {
                LOGERROR("服务操作应答：应答码没有设置/设置格式错误！");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true ||
                _body[KEY_OPTYPE].isIntegral() == false)
            {
                LOGERROR("服务操作应答：服务类型空/格式错误！");
                return false;
            }
            if (_body[KEY_OPTYPE].asInt() == (int)(ServiceOptype::SERVICE_DISCOVERY) &&
                (_body[KEY_METHOD].isNull() == true ||
                 _body[KEY_METHOD].isString() == false ||
                 _body[KEY_HOST].isNull() == true ||
                 _body[KEY_HOST].isArray() == false))
            {
                LOGERROR("服务操作应答：服务需要发现的方法为空/格式错误或ip+端口异常！");
                return false;
            }
            return true;
        }
        // 设置服务类型(服务上线/下线/发现/注册)
        void SetOptype(ServiceOptype optype) { _body[KEY_OPTYPE] = (int)optype; }
        // 设置服务方法
        void SetMethod(const std::string &method) { _body[KEY_METHOD] = method; }
        // 设置服务的ip地址+端口号，应该被保存在一个数组中：
        // {
        //     method : ADD,
        //     host : [
        //         {IP:127.0.0.1, port:8080},
        //         {IP:127.0.0.1, port:8081}
        //     ]
        // }
        void SetHost(std::vector<Address> addrs)
        {
            for (auto &addr : addrs)
            {
                Json::Value val;
                val[KEY_HOST_IP] = addr.first;
                val[KEY_HOST_PORT] = addr.second;
                _body[KEY_HOST].append(val);
            }
        }
        // 获取服务类型、服务方法
        ServiceOptype GetOptype() { return (ServiceOptype)_body[KEY_OPTYPE].asInt(); }
        std::string GetMethod() { return _body[KEY_METHOD].asString(); }
        // 获取能够提供服务的所有服务端信息
        std::vector<Address> GetHosts()
        {
            std::vector<Address> addrs;
            int sz = _body[KEY_HOST].size();
            for (int i = 0; i < sz; i++)
            {
                Address addr;
                addr.first = _body[KEY_HOST][i][KEY_HOST_IP].asString();
                addr.second = _body[KEY_HOST][i][KEY_HOST_PORT].asInt();
                addrs.push_back(addr);
            }
            return addrs;
        }
    };

    // 消息对象的生产工厂
    class MessageFactory
    {
    public:
        // 1. 传递想要创建的消息类型，进行消息对象的创建
        static BaseMessage::ptr CreateMessage(MType mtype)
        {
            switch (mtype)
            {
            case MType::REQ_RPC:
                return std::make_shared<RpcRequest>();
            case MType::RSP_RPC:
                return std::make_shared<RpcResponse>();
            case MType::REQ_TOPIC:
                return std::make_shared<TopicRequest>();
            case MType::RSP_TOPIC:
                return std::make_shared<TopicResponse>();
            case MType::REQ_SERVICE:
                return std::make_shared<ServiceRequest>();
            case MType::RSP_SERVICE:
                return std::make_shared<ServiceResponse>();
            }
            return BaseMessage::ptr();
        }
        // 2. 通过函数模板进行消息对象的创建
        // 如果返回BaseMessage::ptr，那么
        template <typename T, typename... Args>
        static std::shared_ptr<T> CreateMessage(Args... args)
        {
            return std::make_shared<T>(std::forward(args)...);
        }
    };
}